# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: leon

import datetime
import functools
import typing

from coin.exchange.base.kr_rest.options_product import (NativeOptionsProduct,
                                                        NormOptionsProduct,
                                                        OptionsSide,
                                                        parse_options_product_symbol)
import coin.exchange.base.kr_rest.options_product as options_product
from coin.exchange.deribit_v1.kr_rest.currency import DeribitCurrency
from coin.exchange.deribit_v1.kr_rest.futures_constants import (currency_list)
from coin.exchange.deribit_v1.kr_rest.constants import quote_currency_list
import coin.exchange.huobi_futures.kr_rest.contract_util as contract_util


class DeribitOptionsProduct(NativeOptionsProduct):
  _exchange = 'Deribit'
  NativeCurrencyType = DeribitCurrency

  def __init__(self,
               base: DeribitCurrency,
               quote: DeribitCurrency,
               expiry: typing.Union[datetime.datetime, datetime.date, str],
               contract_type: str,
               options_side: OptionsSide,
               strike: float):
    assert quote.currency == 'USD', 'Only USD is supported as quote.'

    # native_expiry_str = contract_util.to_native_expiry_str(expiry, contract_type)
    native_expiry_str = expiry.strftime('%d%b%y').upper().lstrip('0')
    native_symbol = '%s-%s-%s-%s' % (base.currency,
                                     native_expiry_str,
                                     "%d" % strike,
                                     options_product._options_side_str(options_side))

    super().__init__(base=base,
                     quote=quote,
                     expiry=expiry,
                     native_symbol=native_symbol,
                     options_side=options_side,
                     strike=strike)
    self._contract_type = contract_type

  def __repr__(self):
    return str(super().__repr__(self.contract_type))

  @property
  def contract_type(self):
    return self._contract_type

  @classmethod
  @functools.lru_cache(maxsize=256)
  def FromProductImpl(cls, product, current_datetime):
    assert isinstance(product, NormOptionsProduct), type(product)
    assert product.quote.currency == "USD"
    contract_type = contract_util.find_contract_type_from_expiry(current_datetime, product.expiry)
    return cls(product.base, product.quote, product.expiry, contract_type)

  @classmethod
  @functools.lru_cache(maxsize=256)
  def FromStrProductImpl(cls, product, current_datetime):
    assert isinstance(product, str), product

    parsed_result = parse_options_product_symbol(product)
    assert parsed_result['base'] in currency_list, parsed_result['base']
    assert parsed_result['quote'] in quote_currency_list, parsed_result['quote']
    expiry_str = parsed_result['expiry'].lower()
    expiry, contract_type = contract_util.to_expiry_contract_type(expiry_str, current_datetime)

    base = cls.NativeCurrencyType.FromStrCurrency(parsed_result['base'])
    quote = cls.NativeCurrencyType.FromStrCurrency(parsed_result['quote'])

    options_side = parsed_result['options_side']
    strike = parsed_result['strike']

    return cls(base, quote, expiry, contract_type, options_side, strike)

  @classmethod
  @functools.lru_cache(maxsize=256)
  def FromStrNativeProductImpl(cls, product, current_datetime):
    assert isinstance(product, str), product

    lst = product.split('-')
    assert len(lst) == 4, (lst, len(lst))
    base = lst[0]
    assert base in currency_list, base
    quote = 'USD'
    assert quote in quote_currency_list, quote
    expiry_str = lst[1]
    # expiry, contract_type = contract_util.parse_native_expiry_contract_type(expiry_str, current_datetime)
    expiry = datetime.datetime.strptime(expiry_str, '%d%b%y')
    contract_type = 'this_week'
    options_side = OptionsSide(lst[3])
    strike = float(lst[2])

    base = cls.NativeCurrencyType.FromStrNativeCurrency(base)
    quote = cls.NativeCurrencyType.FromStrNativeCurrency(quote)
    return cls(base, quote, expiry, contract_type, options_side, strike)
